package com.shen.library_nettysocket.server

import io.netty.channel.ChannelInboundHandlerAdapter
import io.netty.channel.ChannelHandlerContext
import com.shen.library_nettysocket.protobuf.MessageProtobuf.Msg
import com.alibaba.fastjson.JSON
import com.alibaba.fastjson.JSONObject
import com.shen.library_nettysocket.protobuf.MessageProtobuf
import io.netty.channel.Channel
import java.lang.Exception
import java.util.concurrent.ConcurrentHashMap

internal class ServerHandler : ChannelInboundHandlerAdapter() {

    companion object {
        private val TAG = ServerHandler::class.java.simpleName
    }

    @Throws(Exception::class)
    override fun channelActive(ctx: ChannelHandlerContext) {
        super.channelActive(ctx)
        println("ServerHandler channelActive() -- channel活跃中" + ctx.channel().remoteAddress())
    }

    @Throws(Exception::class)
    override fun channelInactive(ctx: ChannelHandlerContext) {
        super.channelInactive(ctx)
        println("ServerHandler channelInactive() -- channel闲置了")
        ChannelContainer.instance.removeChannelIfConnectNoActive(ctx.channel())     // 用户断开连接后，移除channel
    }

    @Throws(Exception::class)
    override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
        super.exceptionCaught(ctx, cause)
        println("ServerHandler exceptionCaught() -- 异常：${cause.message}")
    }

    @Throws(Exception::class)
    override fun userEventTriggered(ctx: ChannelHandlerContext, evt: Any) {
        super.userEventTriggered(ctx, evt)
        println("ServerHandler userEventTriggered() -- 触发的用户事件")
    }

    @Throws(Exception::class)
    override fun channelRead(ctx: ChannelHandlerContext, msg: Any) {
        var message = msg as Msg
        println("收到来自客户端的消息：$message")

        when (message.head.msgType) {
            1001 -> {
                val fromId = message.head.fromId
                val jsonObj = JSON.parseObject(message.head.extend)
                val token = jsonObj.getString("token")
                val resp = JSONObject()
                if (token == "token_$fromId") {
                    resp["status"] = 1
                    ChannelContainer.instance.saveChannel(NettyChannel(fromId, ctx.channel()))  // 握手成功后，保存「用户通道」
                } else {
                    resp["status"] = -1
                    ChannelContainer.instance.removeChannelIfConnectNoActive(ctx.channel())
                }
                message = message.toBuilder().setHead(message.head.toBuilder().setExtend(resp.toString()).build()).build()

                writeAndFlush(fromId, message)
            }

            1002 -> {                               // 收到心跳消息，原样返回
                writeAndFlush(message.head.fromId, message)
            }

            2001 -> {                               // 收到「2001」或「3001」消息，「返回给·客户端消息」发送「状态报告」
                val fromId = message.head.fromId

                val sentReportMsgBuilder = Msg.newBuilder()                         // 发送消息
                val sentReportHeadBuilder = MessageProtobuf.Head.newBuilder()
                sentReportHeadBuilder.msgId = message.head.msgId
                sentReportHeadBuilder.msgType = 1010
                sentReportHeadBuilder.timestamp = System.currentTimeMillis()
                sentReportHeadBuilder.statusReport = 1
                sentReportMsgBuilder.head = sentReportHeadBuilder.build()


                writeAndFlush(fromId, sentReportMsgBuilder.build())
                // 同时「转发·消息」到「接收方」
                writeAndFlush(message.head.toId, message)
            }

            3001 -> {}

            else -> {}
        }
    }

    /**
     * 根据[userId] 获取  连接的[Channel]
     * 然后发送[message]
     */
    private fun writeAndFlush(userId: String, message: Msg){
        ChannelContainer.instance.getActiveChannelByUserId(userId)!!
            .channel.writeAndFlush(message)
    }

    /**
     * 通道「容器/集合」
     */
    class ChannelContainer private constructor() {

        companion object {
            val instance = ChannelContainer()
        }

        private val CHANNELS: MutableMap<String, NettyChannel> = ConcurrentHashMap()

        /**
         * 保存「通道」 [channel]通道
         */
        fun saveChannel(channel: NettyChannel?) {
            if (channel == null) {
                return
            }
            CHANNELS[channel.channelId] = channel
        }

        /**
         * 移除「通道」当通道无链接时候 [channel]通道
         */
        fun removeChannelIfConnectNoActive(channel: Channel?): NettyChannel? {
            if (channel == null) {
                return null
            }
            val channelId = channel.id().toString()
            return removeChannelIfConnectNoActive(channelId)
        }

        fun removeChannelIfConnectNoActive(channelId: String): NettyChannel? {
            return if (CHANNELS.containsKey(channelId) && CHANNELS[channelId] != null && !CHANNELS[channelId]!!.isActive) {
                CHANNELS.remove(channelId)
            } else null
        }

        fun getUserIdByChannel(channel: Channel): String? {
            return getUserIdByChannel(channel.id().toString())
        }

        fun getUserIdByChannel(channelId: String): String? {
            return if (CHANNELS.containsKey(channelId)) {
                CHANNELS[channelId]!!.userId
            } else null
        }

        /**
         * 根据[userId] 获取  连接的[Channel]
         */
        fun getActiveChannelByUserId(userId: String): NettyChannel? {
            for ((_, value) in CHANNELS) {
                if (value.userId == userId && value.isActive) {
                    return value
                }
            }
            return null
        }
    }

    /**
     * 通道的「信息」实体
     * [userId] 用户ID
     * [channel] 通道
     */
    inner class NettyChannel(var userId: String, var channel: Channel) {
        /** 通道「ID」 */
        val channelId: String
            get() = channel.id().toString()
        /** 通道「是否·连接」 */
        val isActive: Boolean
            get() = channel.isActive
    }
}